package com.stu.javabase;

import java.io.UnsupportedEncodingException;
import java.util.StringJoiner;

/**
 * 包装类型、自动装箱拆箱和String相关演示
 * 涵盖：
 * - int和Integer的区别
 * - 包装类型的作用
 * - 自动装箱和拆箱
 * - String类的特性和常用方法
 * - StringBuffer和StringBuilder的区别
 * - StringJoiner的使用
 * 
 * @author 学习者
 * @version 1.0
 */
public class WrapperTypesAndString {
    
    public static void main(String[] args) {
        System.out.println("=== 包装类型、自动装箱拆箱和String相关演示 ===");
        
        // 1. 包装类型演示
        demonstrateWrapperTypes();
        
        // 2. 自动装箱和拆箱演示
        demonstrateAutoBoxingUnboxing();
        
        // 3. String类演示
        demonstrateString();
        
        // 4. String、StringBuffer、StringBuilder比较
        demonstrateStringComparison();
        
        // 5. StringJoiner演示
        demonstrateStringJoiner();
    }
    
    /**
     * 演示包装类型的特性和用法
     */
    private static void demonstrateWrapperTypes() {
        System.out.println("\n=== 包装类型演示 ===");
        
        // 基本类型 vs 包装类型
        int primitiveInt = 10;
        Integer wrapperInt = new Integer(10); // Java 9后已废弃
        Integer wrapperInt2 = Integer.valueOf(10); // 推荐方式
        Integer wrapperInt3 = 10; // 自动装箱
        
        System.out.println("基本类型int: " + primitiveInt);
        System.out.println("包装类型Integer: " + wrapperInt);
        
        // 包装类型的优势
        System.out.println("\n包装类型的优势：");
        System.out.println("1. 可以为null");
        Integer nullableInt = null;
        System.out.println("   nullableInt = " + nullableInt);
        
        System.out.println("2. 可以作为泛型参数");
        // List<int> list1; // 编译错误
        // List<Integer> list2; // 正确
        
        System.out.println("3. 提供了丰富的工具方法");
        System.out.println("   Integer.MAX_VALUE = " + Integer.MAX_VALUE);
        System.out.println("   Integer.MIN_VALUE = " + Integer.MIN_VALUE);
        System.out.println("   Integer.parseInt(\"123\") = " + Integer.parseInt("123"));
        System.out.println("   Integer.toBinaryString(10) = " + Integer.toBinaryString(10));
        System.out.println("   Integer.toHexString(255) = " + Integer.toHexString(255));
        
        // 所有包装类型
        System.out.println("\n所有包装类型：");
        Byte byteWrapper = 1;
        Short shortWrapper = 2;
        Integer intWrapper = 3;
        Long longWrapper = 4L;
        Float floatWrapper = 5.0f;
        Double doubleWrapper = 6.0;
        Character charWrapper = 'A';
        Boolean booleanWrapper = true;
        
        System.out.println("Byte: " + byteWrapper);
        System.out.println("Short: " + shortWrapper);
        System.out.println("Integer: " + intWrapper);
        System.out.println("Long: " + longWrapper);
        System.out.println("Float: " + floatWrapper);
        System.out.println("Double: " + doubleWrapper);
        System.out.println("Character: " + charWrapper);
        System.out.println("Boolean: " + booleanWrapper);
    }
    
    /**
     * 演示自动装箱和拆箱
     */
    private static void demonstrateAutoBoxingUnboxing() {
        System.out.println("\n=== 自动装箱和拆箱演示 ===");
        
        // 自动装箱（基本类型 -> 包装类型）
        System.out.println("自动装箱：");
        Integer autoBoxed = 100; // 编译器自动调用Integer.valueOf(100)
        System.out.println("int 100 自动装箱为 Integer: " + autoBoxed);
        
        // 自动拆箱（包装类型 -> 基本类型）
        System.out.println("\n自动拆箱：");
        Integer wrapper = 200;
        int autoUnboxed = wrapper; // 编译器自动调用wrapper.intValue()
        System.out.println("Integer 200 自动拆箱为 int: " + autoUnboxed);
        
        // 缓存池演示（-128 ~ 127）
        System.out.println("\n包装类型缓存池演示：");
        Integer a1 = 100;
        Integer a2 = 100;
        Integer a3 = new Integer(100);
        
        System.out.println("Integer a1 = 100; Integer a2 = 100;");
        System.out.println("a1 == a2: " + (a1 == a2)); // true，缓存池
        System.out.println("a1.equals(a2): " + a1.equals(a2)); // true
        
        System.out.println("\nInteger a3 = new Integer(100);");
        System.out.println("a1 == a3: " + (a1 == a3)); // false，new创建新对象
        System.out.println("a1.equals(a3): " + a1.equals(a3)); // true
        
        Integer b1 = 200;
        Integer b2 = 200;
        System.out.println("\nInteger b1 = 200; Integer b2 = 200;");
        System.out.println("b1 == b2: " + (b1 == b2)); // false，超出缓存池范围
        System.out.println("b1.equals(b2): " + b1.equals(b2)); // true
        
        // 自动拆箱的陷阱
        System.out.println("\n自动拆箱的陷阱：");
        Integer nullInteger = null;
        try {
            int value = nullInteger; // 自动拆箱，会抛出NullPointerException
        } catch (NullPointerException e) {
            System.out.println("null的包装类型自动拆箱会抛出NullPointerException");
        }
        
        // 性能考虑
        System.out.println("\n性能考虑：");
        long startTime = System.currentTimeMillis();
        Integer sum1 = 0;
        for (int i = 0; i < 1000000; i++) {
            sum1 += i; // 频繁的装箱拆箱
        }
        long endTime = System.currentTimeMillis();
        System.out.println("使用包装类型累加耗时：" + (endTime - startTime) + "ms");
        
        startTime = System.currentTimeMillis();
        int sum2 = 0;
        for (int i = 0; i < 1000000; i++) {
            sum2 += i; // 直接使用基本类型
        }
        endTime = System.currentTimeMillis();
        System.out.println("使用基本类型累加耗时：" + (endTime - startTime) + "ms");
    }
    
    /**
     * 演示String类的特性
     */
    private static void demonstrateString() {
        System.out.println("\n=== String类演示 ===");
        
        // String的不可变性
        System.out.println("String的不可变性：");
        String str1 = "Hello";
        String str2 = str1;
        str1 = str1 + " World"; // 创建新的String对象
        System.out.println("str1 = " + str1); // Hello World
        System.out.println("str2 = " + str2); // Hello（未改变）
        System.out.println("str1和str2是否为同一对象：" + (str1 == str2)); // false
        
        // String常量池
        System.out.println("\nString常量池：");
        String s1 = "Java";
        String s2 = "Java";
        String s3 = new String("Java");
        String s4 = s3.intern(); // 返回常量池中的引用
        
        System.out.println("s1 == s2: " + (s1 == s2)); // true，常量池
        System.out.println("s1 == s3: " + (s1 == s3)); // false，new创建
        System.out.println("s1 == s4: " + (s1 == s4)); // true，intern返回常量池引用
        
        // String常用方法
        System.out.println("\nString常用方法：");
        String text = "  Hello World Java Programming  ";
        System.out.println("原字符串：'" + text + "'");
        System.out.println("长度：" + text.length());
        System.out.println("去除空格：'" + text.trim() + "'");
        System.out.println("转大写：" + text.toUpperCase());
        System.out.println("转小写：" + text.toLowerCase());
        System.out.println("是否包含'Java'：" + text.contains("Java"));
        System.out.println("是否以'  Hello'开头：" + text.startsWith("  Hello"));
        System.out.println("是否以'  '结尾：" + text.endsWith("  "));
        System.out.println("'Java'的索引：" + text.indexOf("Java"));
        System.out.println("最后一个'a'的索引：" + text.lastIndexOf("a"));
        System.out.println("截取子串(7,12)：'" + text.substring(7, 12) + "'");
        System.out.println("替换'Java'为'Python'：" + text.replace("Java", "Python"));
        
        // 字符串分割
        String[] words = text.trim().split(" ");
        System.out.println("分割后的单词：");
        for (String word : words) {
            System.out.println("  '" + word + "'");
        }
        
        // 字符串反转
        System.out.println("\n字符串反转：");
        String original = "Hello";
        String reversed = new StringBuilder(original).reverse().toString();
        System.out.println("原字符串：" + original);
        System.out.println("反转后：" + reversed);
        
        // 字符串编码转换
        System.out.println("\n字符串编码转换：");
        try {
            String chinese = "你好世界";
            byte[] utf8Bytes = chinese.getBytes("UTF-8");
            byte[] gbkBytes = chinese.getBytes("GBK");
            
            System.out.println("原字符串：" + chinese);
            System.out.println("UTF-8编码长度：" + utf8Bytes.length);
            System.out.println("GBK编码长度：" + gbkBytes.length);
            
            String fromUtf8 = new String(utf8Bytes, "UTF-8");
            String fromGbk = new String(gbkBytes, "GBK");
            System.out.println("从UTF-8解码：" + fromUtf8);
            System.out.println("从GBK解码：" + fromGbk);
        } catch (UnsupportedEncodingException e) {
            System.out.println("编码转换异常：" + e.getMessage());
        }
        
        // String长度限制
        System.out.println("\nString长度限制：");
        System.out.println("String的最大长度理论上是Integer.MAX_VALUE: " + Integer.MAX_VALUE);
        System.out.println("但实际受JVM内存限制，通常小于这个值");
        System.out.println("字符串字面量在编译时受常量池限制，最大65535个字符");
    }
    
    /**
     * 演示String、StringBuffer、StringBuilder的区别
     */
    private static void demonstrateStringComparison() {
        System.out.println("\n=== String、StringBuffer、StringBuilder比较 ===");
        
        // 性能测试
        int iterations = 10000;
        
        // String拼接（效率最低）
        long startTime = System.currentTimeMillis();
        String str = "";
        for (int i = 0; i < iterations; i++) {
            str += "a"; // 每次都创建新对象
        }
        long stringTime = System.currentTimeMillis() - startTime;
        
        // StringBuilder拼接（效率最高，非线程安全）
        startTime = System.currentTimeMillis();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < iterations; i++) {
            sb.append("a");
        }
        String sbResult = sb.toString();
        long sbTime = System.currentTimeMillis() - startTime;
        
        // StringBuffer拼接（效率中等，线程安全）
        startTime = System.currentTimeMillis();
        StringBuffer sbf = new StringBuffer();
        for (int i = 0; i < iterations; i++) {
            sbf.append("a");
        }
        String sbfResult = sbf.toString();
        long sbfTime = System.currentTimeMillis() - startTime;
        
        System.out.println("拼接" + iterations + "次字符'a'的性能对比：");
        System.out.println("String拼接耗时：" + stringTime + "ms");
        System.out.println("StringBuilder拼接耗时：" + sbTime + "ms");
        System.out.println("StringBuffer拼接耗时：" + sbfTime + "ms");
        
        // 特性对比
        System.out.println("\n特性对比：");
        System.out.println("String：");
        System.out.println("  - 不可变，线程安全");
        System.out.println("  - 每次修改都创建新对象");
        System.out.println("  - 适合少量字符串操作");
        
        System.out.println("StringBuilder：");
        System.out.println("  - 可变，非线程安全");
        System.out.println("  - 内部使用字符数组，动态扩容");
        System.out.println("  - 适合单线程大量字符串操作");
        
        System.out.println("StringBuffer：");
        System.out.println("  - 可变，线程安全（方法加synchronized）");
        System.out.println("  - 内部使用字符数组，动态扩容");
        System.out.println("  - 适合多线程大量字符串操作");
        
        // StringBuilder常用方法演示
        System.out.println("\nStringBuilder常用方法：");
        StringBuilder demo = new StringBuilder("Hello");
        System.out.println("初始：" + demo);
        System.out.println("append(' World')：" + demo.append(" World"));
        System.out.println("insert(5, ' Java')：" + demo.insert(5, " Java"));
        System.out.println("delete(5, 10)：" + demo.delete(5, 10));
        System.out.println("reverse()：" + demo.reverse());
        System.out.println("容量：" + demo.capacity());
        System.out.println("长度：" + demo.length());
    }
    
    /**
     * 演示StringJoiner的使用
     */
    private static void demonstrateStringJoiner() {
        System.out.println("\n=== StringJoiner演示 ===");
        
        // 基本用法
        StringJoiner sj1 = new StringJoiner(", ");
        sj1.add("Apple");
        sj1.add("Banana");
        sj1.add("Orange");
        System.out.println("基本用法：" + sj1.toString());
        
        // 带前缀和后缀
        StringJoiner sj2 = new StringJoiner(", ", "[", "]");
        sj2.add("Red");
        sj2.add("Green");
        sj2.add("Blue");
        System.out.println("带前缀后缀：" + sj2.toString());
        
        // 空StringJoiner的默认值
        StringJoiner sj3 = new StringJoiner(", ", "[", "]");
        sj3.setEmptyValue("空列表");
        System.out.println("空StringJoiner：" + sj3.toString());
        
        // 合并StringJoiner
        StringJoiner sj4 = new StringJoiner(", ");
        sj4.add("Java");
        sj4.add("Python");
        
        StringJoiner sj5 = new StringJoiner(", ");
        sj5.add("C++");
        sj5.add("JavaScript");
        
        sj4.merge(sj5);
        System.out.println("合并后：" + sj4.toString());
        
        // 与String.join()比较
        System.out.println("\n与String.join()比较：");
        String[] languages = {"Java", "Python", "C++", "JavaScript"};
        String joined = String.join(", ", languages);
        System.out.println("String.join()结果：" + joined);
        
        System.out.println("\nStringJoiner的优势：");
        System.out.println("1. 可以设置前缀和后缀");
        System.out.println("2. 可以设置空值时的默认显示");
        System.out.println("3. 可以动态添加元素");
        System.out.println("4. 可以合并多个StringJoiner");
    }
}